package com.peachcastle.tools 
{
    import flash.utils.ByteArray;
    
    /**
     * Adler-32 is a modification of the Fletcher checksum. 
     * <p>The <a href="http://en.wikipedia.org/wiki/Adler-32">Adler-32</a> checksum is part of the widely-used zlib compression library, as both were developed by Mark Adler.</p>  
     * <p><b>Example :</b></p>
     * <pre class="prettyprint">
     * package examples 
     * {
     *     import calista.hash.Adler32;
     *     
     *     import flash.display.Sprite;
     *     import flash.utils.ByteArray;
     *     
     *     public class Adler32Example extends Sprite 
     *     {
     *         public function Adler32Example()
     *         {
     *             var bytes:ByteArray = new ByteArray() ;
     *             bytes.writeUTFBytes("Wikipedia") ;
     *             
     *             var sum:uint = Adler32.checkSum(bytes) ;
     *             
     *             trace("Adler32 : " + sum + " 0x" + sum.toString( 16 ).toUpperCase() ) ; // Adler32 : 300286872 0x11E60398
     *         }
     *     }
     * }
     * </pre>
     */
    public final class Adler32 
    {
        /**
         * Generates the checksum of the specified ByteArray with the Adler32 algorithm.
         * 
         * @param buffer the buffer ByteArray object which contains the datas.
         * @param index The index to begin the buffering (default 0).
         * @param length The length value to limit the buffering (if this value is 0, the length of the ByteArray is used).
         */
        public static function checkSum( buffer:ByteArray , index:uint = 0 , length:uint = 0 ):uint 
        {
            if (index >= buffer.length ) 
            { 
                index = buffer.length ; 
            }
            if( length == 0 ) 
            { 
                length = buffer.length - index ; 
            }
            if( ( length + index ) > buffer.length ) 
            { 
                length = buffer.length - index; 
            }
            var l:int ;
            var i:int = index ;
            var a:int = 1 ;
            var b:int = 0 ;
            while ( length ) 
            {
                l    = ( length  > NMAX ) ? NMAX : length ;
                length -= l;
                do 
                {
                    a += buffer[i++] ;
                    b += a ;
                } 
                while ( --l ) ;
                a = (a & 0xFFFF) + (a >> 16) * 15 ;
                b = (b & 0xFFFF) + (b >> 16) * 15 ;
            }
            if (a >= BASE) 
            { 
                a -= BASE ; 
            }
            b = (b & 0xFFFF) + (b >> 16) * 15;
            if (b >= BASE) 
            { 
                b -= BASE ; 
            }
            return (b << 16) | a;
        }
        
        /**
         * The largest prime smaller than 65536.
         */
        private static const BASE:int = 65521 ; 
        
        /**
         * NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
         */
        private static const NMAX:int = 5552 ;
    }

}